/*!
 * jQuery axzoomer
 * Alban Xhaferllari
 * albanx@gmail.com
 * Copyright 2010, AUTHORS.txt (http://www.albanx.com)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * 
 */

(function($)
{
        var methods =
        {
                init : function(options)
                {
                    var settings = 
                    {
                        'maxZoom':4,
                        'zoomIn':'',
                        'zoomOut':'',
                        'opacity':0.5,
                        'sensivity':10, 
                        'width':500, // added by heston sinuraya
                        'height':300, // added by heston sinuraya
                    };
            return this.each(function() 
            {
                                if(options) $.extend(settings,options);//extends default options
                                        
                                if(this.tagName.toLowerCase()!='img')
                                {
                                        //$.error('3dzoomer plugin applies only to img tag.');
          alert('3dzoomer plugin applies only to img tag.');
                                        return false;
                                }
                                var $this=$(this).addClass('ax-zoom').css({position:'absolute',top:0,left:0});

                                $this.LOADING=true;
                                /**************Detect device type, normal mouse or touchy*******/
                                var touchy=(/iphone|ipod|ipad|android/i).test(navigator.userAgent);
                                
                                var move='mousemove';
                                var end='mouseup';
                                var down='mousedown';

                                if(touchy)
                                {
                                        move='touchmove';
                                        end='touchend';
                                        down='touchstart';
                                }
                                /***************************************************************/
                                
                                /*******************Create containers*************************/
                                //div contenitor
                                var container=$('<div />').appendTo($this.parent())
                                                                                  //.css({'position':'relative','left':0,'top':0, 'margin':'0px auto'})
                                                                                  .css({'width':settings.width,'height':settings.height,'left':0,'top':0, 'margin':'0px auto'})
                                                                                  .hover(function(){
                                                                                          $this.controlsDiv.show('fade');
                                                                                  },function(){
                                                                                          $this.controlsDiv.hide('fade');
                                                                                  });
                                //div window for zoom view
                                var windowDiv=$('<div />').css({overflow:'hidden','position':'absolute','left':0,'top':0})
                                                                                  .appendTo(container)//attach to first parent
                                                                                  .append($this);//the move img to div
                                /**************************************************************/
                                
                                /*******************Create controls divs and buttons****************/
                                //Div containing buttons and controls
                                var controlsDiv=$('<div class="ax-controls"/>').appendTo(container).hide()
                                                                                        .css({'position':'absolute','opacity':settings.opacity});
                                $this.controlsDiv=controlsDiv;
                                
                                //function to zoom on button down using timers
                                var zoomtimer;
                                $this.controlZoom=function(x)
                                {
                                        $this.zoomInOut(x);
                                        zoomtimer=setTimeout(function(){
                                                $this.controlZoom(x);
                                        },30); 
                                };
                                
                                //zoom in button                                                        
                                var zoombut_in=(settings.zoomIn!='')?$('<img src="'+settings.zoomIn+'" />'):$('<input type="button" value="+"/>');
                                zoombut_in.appendTo(controlsDiv).css('cursor','pointer')
                                                  .bind(down,function(e){
                                                          e.stopPropagation();
                                                          MOUSEX=MAIN_WIDTH/2;
                                                          MOUSEY=MAIN_HEIGHT/2;
                                                          $this.controlZoom(0.05);
                                                  })
                                                  .bind(end,function(){
                                                           clearTimeout(zoomtimer);
                                                   });                          
                                
                                //zoom out button
                                var zoombut_out=(settings.zoomOut!='')?$('<img src="'+settings.zoomOut+'" />'):$('<input type="button" value="-"/>');
                                zoombut_out.appendTo(controlsDiv).css('cursor','pointer')
                                                   .bind(down,function(e){
                                                           e.stopPropagation();
                                                           MOUSEX=MAIN_WIDTH/2;
                                                           MOUSEY=MAIN_HEIGHT/2;
                                                           $this.controlZoom(-0.05);
                                                   })
                                                   .bind(end,function(){
                                                           clearTimeout(zoomtimer);
                                                   });
                                /***********************************************************************/
                                
                                /************get actual image data*****************************/
                                //window DIV coordinates to the document                        
                                var MAIN_WIDTH=$this.width();
                                var MAIN_HEIGHT=$this.height();
                                //var MAIN_WIDTH=settings.width();
                                //var MAIN_HEIGHT=settings.height();

                                
                                var CURR_W=MAIN_WIDTH;//curr dims img
                                var CURR_H=MAIN_HEIGHT;
                                
                                var MAIN_SRC=$this.attr('src');//normal size source
                                var ZOOM_SRC=$this.attr('src-big');//hight resolution source of image
                                var img_ext=MAIN_SRC.split('.').pop();//image extension jpg, gif...
                                
                                $this.setup=function()//funtion that sets the size of window div
                                {
                                        windowDiv.css({'width':MAIN_WIDTH, 'height':MAIN_HEIGHT});
                                        windowDiv.css({'left':(settings.width-windowDiv.width())/2-10,'top':0}); // changed by heston sinuraya
                                        //setting left so to center the tools 
                                        controlsDiv.css({'height':35,'top':settings.height-100,'left':(settings.width-controlsDiv.width())/2}); // changed by heston sinuraya
                                        CURR_W=MAIN_WIDTH;//curr dims img
                                        CURR_H=MAIN_HEIGHT;
                                };              
                                
                                //chrome gives 0 width with width get so we preload image before to get real
                                //size if they are not set on image attr
                                if(MAIN_WIDTH==0 || MAIN_WIDTH==null || MAIN_HEIGHT==0 || MAIN_HEIGHT==null)
                                {
                                        $this.LOADING=true;
                                        var tmp=new Image();
                                        tmp.onload=function()
                                        {
                                                MAIN_WIDTH=this.width;
                                                MAIN_HEIGHT=this.height;
                                                $this.LOADING=false;
                                                $this.setup();
                                        };
                                        tmp.src=MAIN_SRC;
                                }
                                else
                                {
                                        $this.setup();
                                        
                                }
                                /**************************************************************/
                                var MAIN_TOP=0,MAIN_LEFT=0;
                                //function to get MOUSEX, MOUSEY postiion relative to window
                                //or to get touchx,y medium coordinates on more than one touche
                                var TOUCHNUM=0;
                                function medium_coors(e,rel2obj)
                                {
                                        if(rel2obj && (MAIN_TOP==0 || MAIN_LEFT==0))//calculate once for perfomance
                                        {
                                                MAIN_TOP=$(rel2obj).offset().top;
                                                MAIN_LEFT=$(rel2obj).offset().left;
                                        }
                                        
                                        TOUCHNUM=1;
                                        if(touchy)
                                        {
                                                e=e.originalEvent;
                                                TOUCHNUM=e.touches.length;
                                                var minx=9999,maxx=-9999,miny=9999,maxy=-9999;
                                                
                                                for(var i=0;i<e.touches.length;i++)
                                                {
                                                        minx=Math.min(minx,e.touches[i].pageX-MAIN_LEFT);
                                                        maxx=Math.max(maxx,e.touches[i].pageX-MAIN_LEFT);
                                                        miny=Math.min(miny,e.touches[i].pageY-MAIN_TOP);
                                                        maxy=Math.max(maxy,e.touches[i].pageY-MAIN_TOP);
                                                }
                                                
                                                return [(minx+maxx)/2,(miny+maxy)/2,e.touches.length];
                                        }
                                        else
                                        {
                                                return [e.pageX-MAIN_LEFT,e.pageY-MAIN_TOP,1];
                                        }
                                }
                                /******************************************************/
                                
                                var ZOOM=false;
                                var START_X=0;//start X move position
                                var START_Y=0;//start Y move position
                                
                                var MOUSEX=0;//mouse X relative to window DIV
                                var MOUSEY=0;//mouse Y relative to window DIV
                                
                                var CURR_Y=0;//curr pos of img relative to window DIV
                                var CURR_X=0;//obiusvly is 0 0 at start
                                
                                var ENABLE_DRAG=false;
                                //mouse down
                                windowDiv.bind(down,function(e){
                                        e.preventDefault();
                                        //get starting position relative to windowDiv always
                                        CURR_X=$this.get(0).offsetLeft;
                                        CURR_Y=$this.get(0).offsetTop;
                                        CURR_W=$this.width();
                                        CURR_H=$this.height();
                                        
                                        //update and get image position, dimensions
                                        var coors=medium_coors(e,this);
                                        START_X=coors[0];
                                        START_Y=coors[1];
                                        ENABLE_DRAG=true;
                                        //$this.drag();
                                        
                                });
                                
                                //mouse move get only mouse coordinates
                                windowDiv.bind(move,function(e){
                                        e.preventDefault();
                                        
                                        var coors=medium_coors(e,this);
                                        MOUSEX=coors[0];
                                        MOUSEY=coors[1];
                                        $this.drag();
                                });
                                
                                //timer for drag for better performance
                                var dragTimer;
                                windowDiv.bind(end,function(e){
                                        ENABLE_DRAG=false;//clearTimeout(dragTimer);//clear timer on mouseup
                                        clearTimeout(zoomtimer);
                                });
                                $(document).bind(end,function(ev){
                                        ENABLE_DRAG=false;//clearTimeout(dragTimer);
                                        clearTimeout(zoomtimer);
                                });
                                
                                $this.drag=function()
                                {
                                        if(ENABLE_DRAG)
                                        {
                                                var new_x=MOUSEX-START_X+CURR_X;
                                                //set drag limits
                                                new_x=Math.min(new_x,0);
                                                new_x=Math.max(new_x,MAIN_WIDTH-CURR_W);
                                                
                                                var new_y=MOUSEY-START_Y+CURR_Y;
                                                //set drag limits
                                                new_y=Math.min(new_y,0);
                                                new_y=Math.max(new_y,MAIN_HEIGHT-CURR_H);
                                                $(this).css({'top':new_y, 'left':new_x});
                                        }
                                        /*dragTimer = setTimeout(function () {
                                                $this.drag();
                                        }, 30);*/
                                };                      
                                
                                //zooom on double click only on normal not ipad
                                windowDiv.bind('dblclick',function(e){
                                        var coors=medium_coors(e,this);
                                        MOUSEX=coors[0];
                                        MOUSEY=coors[1];
                                        $this.zoomInOut(1);
                                });                                                                     
                                /******************************ZOOOM FUNCTIONS****************************/     
                                if(touchy)
                                {
                                        windowDiv.get(0).ongesturechange=function(e)
                                        {
                                                e.preventDefault();
                                                if(TOUCHNUM>=2) 
                                                {
                                                        var delta=(e.scale<1)?-1:1;
                                                        $this.zoomInOut(delta/12);
                                                }
                                                else if(TOUCHNUM>=3)
                                                {
                                                          $this.css('webkitTransform',  "rotate(" + ((e.rotation) % 360) + "deg)");
                                                }
                                        };
                                }
                                else
                                {
                                        windowDiv.mousewheel(function(e,delta) { 
                                                e.preventDefault();
                                                $this.zoomInOut(delta/settings.sensivity);                                              
                                        });
                                }                       
                                
                                $this.zoomLevel=1;
                                var timeoutloader;
                            
                                $this.zoomInOut=function (zoom)
                                {
                                        clearTimeout(timeoutloader);
                                        
                                        //calculate new dims
                                        CURR_W=$this.width();
                                        CURR_H=$this.height();
          
                                        var new_w=Math.max(CURR_W*(1+zoom),MAIN_WIDTH);//limit dim to original in small
                                        var new_h=Math.max(CURR_H*(1+zoom),MAIN_HEIGHT);
                                        
                                        /*still buggy*/
                                        //get current dims and position
                                       CURR_X=$this.get(0).offsetLeft;
                                       CURR_Y=$this.get(0).offsetTop;
                                       
                                       //calculate new position
                                        var tmpx=zoom*(CURR_X-MOUSEX)+CURR_X;
                                        var disX=MAIN_WIDTH-tmpx;//distance betwen top of img and mainX
                                        if(new_w<disX) tmpx+=disX-new_w;//caculate new x to mantain inside windowDiv visibility
                                        var new_x=Math.min(tmpx,0);//limit x to 0 coordinate in positive
                                        
                                        var tmpy=zoom*(CURR_Y-MOUSEY)+CURR_Y;
                                        var disY=MAIN_HEIGHT-tmpy;
                                        if(new_h<disY)  tmpy+=disY-new_h;
                                        var new_y=Math.min(tmpy,0); 
                                        
                                        if(Math.round(new_w/MAIN_WIDTH)<=settings.maxZoom)
                                        {
                                                $this.zoomLevel=new_w/MAIN_WIDTH;
                                                //windowDiv.css({width:new_w,height:new_h,top:(settings.height-new_h)/2-35,left:(settings.width-new_w)/2-10}); //added by heston sinuraya
                                                newContainerWidth = settings.width;
                                                newContainerHeight = settings.height;
                                                if (new_w <= settings.width) {
                                                  newContainerWidth = new_w;
                                                }
                                                if (new_h <= settings.height) {
                                                  newContainerHeight.width = new_h;
                                                }
                                                windowDiv.css({width:newContainerWidth,height:newContainerHeight,'top':0,'left':(settings.width-windowDiv.width())/2}); //added by heston sinuraya
                                                $this.css({width:new_w,height:new_h,top:new_y,left:new_x});
                                                //$this.css({width:new_w,height:new_h,top:100,left:100});
                                    timeoutloader = setTimeout(function () {
                                        $this.preload_zoom();//preload zoom image meanwhile
                                    }, 500);
                                        }
                                                        
                                };
                                
                                /*
                                 * preload zoom images
                                 */
                                $this.preload_zoom=function ()
                                {
                                        if($this.zoomLevel>1.2 && ZOOM_SRC!='' && ZOOM_SRC!=null)//preload only if zoom is bigger than 1.2
                                        {
                                                var load=new Image();
                                                load.onload=function()
                                                {
                                                        $this.attr('src',ZOOM_SRC);
                                                };
                                                load.src=ZOOM_SRC;
                                        }
                                        else if($this.zoomLevel==1)
                                        {
                                                $this.attr('src',MAIN_SRC);
                                        }
                                };      
                                
            });
                },
                enable:function()
                {
                        return this.each(function()
                        {
                                var $this = $(this);
                        });
                },
                disable:function()
                {
                        return this.each(function()
                        {
                                var $this = $(this);
                        });
                },
                destroy : function()
                {
                        return this.each(function()
                        {
                                var $this = $(this);
                                $this.removeData('settings');
                        });
                },
                option : function(option, value)
                {
                        return this.each(function(){
                                var $this=$(this);
                        });
                }
        };

        $.fn.axzoomer = function(method, options)
        {
                if(methods[method])
                {
                        return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
                }
                else if(typeof method === 'object' || !method)
                {
                        return methods.init.apply(this, arguments);
                }
                else
                {
                        $.error('Method ' + method + ' does not exist on jQuery.zoomer3d');
                }
        };

})(jQuery);